﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Collections.ObjectModel;
using WTwitter.Model.Framework;
using WTwitter.Model.UserData;
using WTwitter.Model.Utility;
using WTwitter.Model.Twitter.Utility;
using System.Text.RegularExpressions;
using System.ComponentModel;

namespace WTwitter.ViewModel {
	sealed public class SubmitPanelViewModel : ClosableViewModelBase {
		private enum SubmitMode {
			Tweet,
			Reply,
			ReTweet,
			DirectMessage,
		}

		#region private member
		private ICommand _submitCommand;
		private ICommand _shotenUrlCommand;
		private ICommand _replyCommand;
		private ICommand _reTweetCommand;
		private ICommand _directMessageCommand;
		private AuthInfo _userInfo;
		private ITimelineItem _replyTo;
		private string _editingText = "";
		private SubmitMode _mode = SubmitMode.Tweet;
		private readonly int TextLengthLimit = 140;
		private string _statusMessage;
		private object _lockForIsBusy = new object();
		#endregion

		#region Property
		/// <summary>
		/// 入力中のテキスト
		/// </summary>
		public string EditingText {
			get { return _editingText; }
			set {
				if (_editingText != value) {
					_editingText = value;
					OnPropertyChanged("EditingText");
					TextLimitRemain = TextLengthLimit - EditingText.Length;
					OnPropertyChanged("TextLimitRemain");
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public string StatusMessage {
			get { return _statusMessage; }
			set {
				if (_statusMessage != value) {
					_statusMessage = value;
					OnPropertyChanged("StatusMessage");
				}
			}
		}

		private bool IsBusy {
			set;
			get;
		}

		public int TextLimitRemain { private set; get; }

		public TimelineViewModel Timeline {get; set;}
		#endregion

		#region Command
		/// <summary>
		/// 投稿
		/// </summary>
		public ICommand SubmitCommand {
			get {
				if (_submitCommand == null) {
					_submitCommand = new RelayCommand(	param => this.Submit(), param => this.CanSubmit);
				}
				return _submitCommand;
			}
		}

		/// <summary>
		/// 編集中のテキスト中のURL短縮
		/// </summary>
		public ICommand ShortenUrlCommand {
			get {
				if (_shotenUrlCommand == null) {
					_shotenUrlCommand = new RelayCommand(param => this.ShortenUrl()	);
				}
				return _shotenUrlCommand;
			}
		}

		/// <summary>
		/// 返信対象のアイテムがあるときは、それに対する返信に編集中テキストを変更する
		/// </summary>
		public ICommand ReplyCommand {
			get {
				if (_replyCommand == null) {
					_replyCommand = new RelayCommand(param => this.SetTextToReply(), param => _replyTo != null);
				}
				return _replyCommand;
			}
		}

		/// <summary>
		/// 返信対象のアイテムがあるときは、それをReTweetするように変更する
		/// </summary>
		public ICommand ReTweetCommand {
			get {
				if (_reTweetCommand == null) {
					_reTweetCommand = new RelayCommand(param => this.SetTextToReTweet(), param => _replyTo != null);
				}
				return _reTweetCommand;
			}
		}

		public ICommand DirectMessageCommand {
			get {
				if (_directMessageCommand == null) {
					_directMessageCommand = new RelayCommand(param => this.SetTextToMail(), param => _replyTo != null);
				}
				return _directMessageCommand;
			}
		}
		#endregion

		#region Constructor
		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="info">ユーザー認証情報</param>
		public SubmitPanelViewModel(AuthInfo info) 
			:this(info, null,null) {
		}

		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="info">ユーザー認証情報</param>
		/// <param name="replyTo">返信対象のアイテム</param>
		/// <param name="referenceTimeline">投稿入力時に参照情報として表示するアイテムを含んだタイムライン</param>
		public SubmitPanelViewModel(AuthInfo info, ITimelineItem replyTo,TimelineViewModel referenceTimeline) 
			: base("投稿") {
			Timeline = referenceTimeline;
			_userInfo = info;
			_replyTo = replyTo;
			TextLimitRemain = 140;
		}
		#endregion

		#region public Method
		/// <summary>
		/// 投稿する
		/// </summary>
		public void Submit() {
			lock(_lockForIsBusy) {
				if (IsBusy) {
					StatusMessage = "今は実行できません";
					return;
				} else {
					IsBusy = true;
				}
			}
			var worker = new BackgroundWorker();
			worker.DoWork += (sender, e) => {
				try {
					StatusMessage = "投稿しています...";
					switch (_mode) {
						case SubmitMode.Tweet:
							e.Result = StatusMethods.Update(_editingText, _userInfo);
							break;
						case SubmitMode.Reply:
							e.Result = StatusMethods.Update(EditingText, _replyTo.Id, _userInfo);
							break;
						case SubmitMode.ReTweet:
							e.Result = StatusMethods.Update(EditingText, _userInfo);
							break;
						case SubmitMode.DirectMessage:
							e.Result = DirectMessageMethod.New(_replyTo.User.ScreenName, EditingText, _userInfo);
							break;
						default:
							throw new InvalidOperationException();
					}
				} catch (Exception exception) {
					e.Result = exception;
				}
			};
			worker.RunWorkerCompleted += (sender, e) => {
				lock (_lockForIsBusy) {
					IsBusy = false;
				}
				if (e.Result is Exception) {
					StatusMessage = "投稿に失敗しました";
				} else {
					StatusMessage = "投稿が完了しました";
					Close();
				}
			};
			worker.RunWorkerAsync();
		}

		/// <summary>
		/// 投稿できる状態かどうかの判断
		/// </summary>
		public bool CanSubmit {
			get { return _editingText.Length > 0 && !IsBusy; }
		}

		/// <summary>
		/// 編集中のテキストに含まれるURLを短縮サービスにアクセスして短くする
		/// </summary>
		public void ShortenUrl() {
			var worker = new BackgroundWorker();
			lock(_lockForIsBusy) {
				if (IsBusy) {
					StatusMessage = "今は実行できません";
					return;
				} else {
					IsBusy = true;
				}
			}
			worker.DoWork += (sender , e) => {
				try {
					StatusMessage = "URL短縮サービスにアクセスしています";
					var regex = new Regex(RegexPatterns.UrlPattern);
					var matches = regex.Matches(this.EditingText);
					foreach (Match m in matches) {
						var shortUrl = BitlyUtility.Shorten(m.Value, Option.Instance.Bitly);
						EditingText = EditingText.Replace(m.Value, shortUrl);
					}
				} catch (Exception exception) {
					e.Result = exception;
				}
			};
			worker.RunWorkerCompleted += (sender, e) => {
				lock (_lockForIsBusy) {
					IsBusy = false;
				}
				if (e.Result is Exception) {
					StatusMessage = "URL短縮に失敗しました";
				} else {
					StatusMessage = "URL短縮が完了しました";
				}
			};
			worker.RunWorkerAsync();
		}

		public bool CanShortenUrl {
			get { return !IsBusy; }
		}

		public void SetTextToReply() {
			EditingText = string.Format("@{0} ", _replyTo.User.ScreenName);
			DisplayName = string.Format("@{0}へ返信", _replyTo.User.ScreenName);
			_mode = SubmitMode.Reply;
		}

		public void SetTextToMail() {
			EditingText = "";
			DisplayName = string.Format("@{0}へダイレクトメッセージ", _replyTo.User.ScreenName);
			_mode = SubmitMode.DirectMessage;
		}

		public void SetTextToReTweet() {
			EditingText = string.Format("RT @{0}: {1}", _replyTo.User.ScreenName, _replyTo.Text);
			DisplayName = string.Format("@{0}の発言をReTeweet", _replyTo.User.ScreenName);
			_mode = SubmitMode.ReTweet;
		}

		public override string ToString() {
			return "SubmitPanelViewModel";
		}
		#endregion


	}
}
